package scm.erp.core.mybatis.type;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;

public class CmEnumValueTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
    private final Class<E> type;
    private final E[] enums;

    public CmEnumValueTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("类型参数不能为空!");
        }
        this.type = type;
        this.enums = type.getEnumConstants();
        if (this.enums == null) {
            throw new IllegalArgumentException(type.getSimpleName() + " 不是合法的枚举类型!");
        }
    }

    @Override
    public void setNonNullParameter(
            PreparedStatement ps,
            int i,
            E parameter,
            JdbcType jdbcType) throws SQLException {
        try {
            Method method = type.getDeclaredMethod("getValue");
            Object invoke = method.invoke(parameter);
            if (invoke instanceof Integer) {
                ps.setInt(i, (Integer) invoke);
            } else if (invoke instanceof String) {
                ps.setString(i, (String) invoke);
            } else if (invoke instanceof Boolean) {
                ps.setBoolean(i, (Boolean) invoke);
            } else if (invoke instanceof BigDecimal) {
                ps.setBigDecimal(i, (BigDecimal) invoke);
            } else {
                throw new IllegalArgumentException("不支持此枚举类型!");
            }

        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new IllegalArgumentException("未定义getValue方法!");
        }

    }

    @Override
    public E getNullableResult(
            ResultSet rs,
            String columnName) throws SQLException {
        Object value = rs.getObject(columnName);
        return toValueEnum(value);
    }

    @Override
    public E getNullableResult(
            ResultSet rs,
            int columnIndex) throws SQLException {
        Object value = rs.getObject(columnIndex);

        return toValueEnum(value);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        Object value = cs.getObject(columnIndex);
        return toValueEnum(value);
    }

    private E toValueEnum(Object value) {
        if (value == null) {
            return null;
        }
        try {
            for (E e : this.enums) {
                Method method = type.getDeclaredMethod("getValue");
                Object invoke = method.invoke(e);
                if (Objects.equals(invoke, value)) {
                    return e;
                }
            }
            throw new IllegalArgumentException("不能转换" + value + " 为 " + type.getSimpleName() + " by value.");
        } catch (Exception ex) {
            throw new IllegalArgumentException("不能转换" + value + " 为 " + type.getSimpleName() + " by value.", ex);
        }
    }
}
